﻿using BCCommon;
using BCCommon.Enums;
using BCCommon.Extensions;
using BCCommon.PaymentEnums;
using BCCommon.TMS.Order;
using BCDto.Common.ErrorMessage;
using BCDto.Common.Payment.Payment;
using BCDto.Common.Payment.PaymentRecord;
using BCDto.TMS.Order;
using BCDto.TMS.Order.OrderExtention;
using BCDto.TMS.Order.OrderProcess;
using BCService.Common.Payment.Payment;
using BCService.Common.Payment.PaymentRecord;
using BCService.TMS.Order.Order;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;

namespace BCTMSRESTful.Controllers.DriverApp
{
    /// <summary>
    /// 支付接口--司机端
    /// </summary>
    [ApiExplorerSettings(GroupName = "DriverApp")]
    [Route("api/v1/DriverApp/[controller]")]
    public class PaymentsController : DriverAppBaseController
    {
        private readonly IPaymentService paymentService;
        private readonly IOrderProcessService orderProcessService;
        private readonly ICommonPaymentRecordService commonPaymentRecordService;

        public PaymentsController(IPaymentService paymentService, IOrderProcessService orderProcessService, ICommonPaymentRecordService commonPaymentRecordService)
        {
            this.paymentService = paymentService;
            this.orderProcessService = orderProcessService;
            this.commonPaymentRecordService = commonPaymentRecordService;

        }

        #region 获取可用支付渠道
        /// <summary>
        /// 获取可用的付款渠道。
        /// </summary>
        /// <param name="orderType">订单类型。</param>
        /// <param name="osType">操作系统。</param>
        /// <param name="deviceType">设备类型。</param>
        /// <response code="200">付款渠道列表。</response>
        /// <returns></returns>
        [HttpGet("[action]")]
        [ProducesResponseType(typeof(IEnumerable<ChannelDto>), 200)]
        public IActionResult Channels([FromQuery(Name = "order_type")] FlowType orderType, [FromQuery(Name = "os_type")] SourceOSType osType, [FromQuery(Name = "device_type")] DeviceType deviceType)
        {
            var channels = this.paymentService.GetChannels(SourceAppType.DriverApp, orderType, osType, this.UserInfo);

            return this.Ok(channels);
        }
        #endregion

        #region 获取订单、代收货款、订单和代收货款的付款二维码
        /// <summary>
        ///  获取订单、代收货款、订单和代收货款的付款二维码
        /// </summary>
        /// <param name="paymentRequestDto">付款请求信息。</param>
        /// <response code="200">订单付款二维码信息。</response>
        /// <response code="400">请求参数或输入的数据不正确。</response>
        /// <response code="401">请求需要认证或者认证信息已过期。</response>
        /// <response code="403">无权访问指定的功能。</response>
        /// <response code="500">服务器发生错误。</response>
        /// <response code="501">某些功能尚未实现。</response>
        /// <returns></returns>
        [HttpPost("[action]")]
        [ProducesResponseType(typeof(PaymentQRCodeDto), 200)]
        [ProducesResponseType(typeof(ErrorMessageDto), 400)]
        [ProducesResponseType(typeof(ErrorMessageDto), 500)]
        public IActionResult OrderQRCode([FromBody] PaymentRequestDto paymentRequestDto)
        {
            IChannelFactoryService channelFactoryService = this.paymentService.GetChannelService(SourceAppType.DriverApp, paymentRequestDto.ChannelType, paymentRequestDto.OSType);
            if (channelFactoryService == null)
            {
                throw new ArgumentException("选定的付款渠道暂时无法使用。");
            }
            OrderDto orderDto = this.orderProcessService.GetOrder(paymentRequestDto.ReferenceNumber);
            if (paymentRequestDto.OrderType != FlowType.TMSOrderSecondWeight)
            {
                FlowType[] paymentOrderTypes = new FlowType[] { FlowType.CodAndOrder, FlowType.Cod, FlowType.TMSOrder };
                if (!paymentRequestDto.OrderType.In(paymentOrderTypes))
                {
                    throw new ArgumentException("订单类型仅支持订单及代收货款，不支持其他类型");
                }
                if (orderDto.PayMode == PayMode.CurrentlyPay && paymentRequestDto.OrderType != FlowType.TMSOrder)
                {
                    if (!orderDto.IsCod)
                    {
                        throw new ArgumentException("现付订单收款类型仅支持订单，不支持其他类型");
                    }
                }
                if (orderDto.PayMode == PayMode.Collect && (paymentRequestDto.OrderType != FlowType.TMSOrder && paymentRequestDto.OrderType != FlowType.CodAndOrder))
                {
                    throw new ArgumentException("货到付款订单收款类型仅支持订单或代收货款,不支持其他类型");
                }
                string ip = Request.HttpContext.Connection.RemoteIpAddress.ToString();
#if DEBUG
                ip = "192.168.1.1";
#endif
                bool paidExists = this.orderProcessService.CheckOrderPaid(orderDto.OrderNo);
                if (paidExists)
                {
                    throw new ArgumentException("订单已支付，无需重复操作");
                }
                this.UserInfo.AddressIp = ip;

                return this.Ok(this.orderProcessService.CreatePaymentQRCode(SourceAppType.DriverApp, this.UserInfo, this.Driver, paymentRequestDto, channelFactoryService));
            }
            else
            {
                throw new NotImplementedException();
            }
        }
        #endregion

        #region 支付宝订单交易结果查询--二维码付款后只能使用此操作查询支付结果
        /// <summary>
        /// 支付宝订单交易结果查询
        /// 用于支付宝二维码收款支付验签
        /// </summary>
        /// <param name="alipayCheckOrderPaymentResultDto">阿里支付检查订单支付结果模型</param>
        /// <returns>此接口成功后会返回支付宝查询结果</returns>
        [HttpPost("[action]")]
        [ProducesResponseType(typeof(OrderDto), 200)]
        [ProducesResponseType(typeof(ErrorMessageDto), 400)]
        [ProducesResponseType(typeof(ErrorMessageDto), 500)]
        public IActionResult AlipayCheckOrderPaymentResult([FromBody] AlipayCheckOrderPaymentResultDto alipayCheckOrderPaymentResultDto)
        {
            AlipayService alipayService = (AlipayService)this.paymentService.GetChannelService(SourceAppType.DriverApp, PaymentChannelType.Alipay, alipayCheckOrderPaymentResultDto.OSType);
            dynamic result = alipayService.GetAlipayRecordInfo(alipayCheckOrderPaymentResultDto.OutTradeNo, alipayCheckOrderPaymentResultDto.TradeNo);
            if (result.alipay_trade_query_response.code == "10000")
            {
                if (result.alipay_trade_query_response.trade_status != "TRADE_SUCCESS")
                {
                    throw new ArgumentException("支付宝交易查询失败");
                }
                this.commonPaymentRecordService.UpodatePaymentRecordCheckSignTime(long.Parse(alipayCheckOrderPaymentResultDto.OutTradeNo));
                PaymentRecordDto paymentRecordDto = this.commonPaymentRecordService.UpdatePaymentRecordStatusSuccess(long.Parse(alipayCheckOrderPaymentResultDto.OutTradeNo));
                OrderDto orderDto = this.orderProcessService.GetOrder(paymentRecordDto.ReferenceNumber);
                if (paymentRecordDto.OrderType == FlowType.TMSOrder)
                {
                    //查询支付记录的订单类型为订单的：
                    //1.现付，那就自动调用出发。
                    //2.到付，仅更新收货人付款时间
                    if (orderDto.PayMode == PayMode.CurrentlyPay)
                    {
                        if (!orderDto.ShippingPayTime.HasValue)
                        {
                            orderDto = this.orderProcessService.CheckSignCompleteToProcessOrderInformation(OrderPayer.Shipper, orderDto.OrderNo, paymentRecordDto.PaymentRecordId, PaymentChannelType.Alipay, paymentRecordDto.Amount);
                        }
                        int minIndex = orderDto.OrderExtentionInfo.Min(p => p.EndIndex);
                        OrderExtentionDto orderExtentionDto = orderDto.OrderExtentionInfo.Single(p => p.EndIndex == minIndex);
                        OrderStartOutRequestDto orderStartOutRequestDto = new OrderStartOutRequestDto()
                        {
                            AddressType = AddressType.Take,
                            OrderExtentionId = orderExtentionDto.OrderExtentionId,
                            OrderNo = orderDto.OrderNo
                        };
                        return Ok(this.orderProcessService.StartOut(this.Driver, orderStartOutRequestDto));
                    }
                    else if (orderDto.PayMode == PayMode.Collect)
                    {
                        if (!orderDto.ConsigneePayTime.HasValue)
                        {
                            orderDto = this.orderProcessService.CheckSignCompleteToProcessOrderInformation(OrderPayer.Receiver, orderDto.OrderNo, paymentRecordDto.PaymentRecordId, PaymentChannelType.Alipay, paymentRecordDto.Amount);
                        }
                        return Ok(orderDto);
                    }
                    throw new ArgumentException("回单付业务不存在收款");
                }
                else if (paymentRecordDto.OrderType == FlowType.Cod)
                {
                    return Ok(this.orderProcessService.UpdateCodStatusAndTime(orderDto.OrderId, paymentRecordDto.PaymentRecordId));
                }
                else if (paymentRecordDto.OrderType == FlowType.CodAndOrder)
                {
                    //订单和代收货款只存在于收货人付款，并且有代收货款金额的。
                    if (orderDto.PayMode == PayMode.Collect)
                    {
                        if (!orderDto.ConsigneePayTime.HasValue)
                        {
                            orderDto = this.orderProcessService.CheckSignCompleteToProcessOrderInformation(OrderPayer.Receiver, orderDto.OrderNo, paymentRecordDto.PaymentRecordId, PaymentChannelType.Alipay, paymentRecordDto.Amount);
                        }
                        return Ok(orderDto);
                    }
                    throw new ArgumentException("订单及代收货款合并收款，仅支持到付业务");
                }
            }
            throw new ArgumentException("收款查询失败");
        }

        #region 微信订单交易结果查询--二维码付款后只能使用此操作查询支付结果
        /// <summary>
        /// 微信订单交易结果查询
        /// 用于二维码付款后只能使用此操作查询支付结果。
        /// </summary>
        /// <param name="weipayCheckPaymentResultDto">微信验证支付结果对象</param>
        /// <response code="200">支付效验通过或不通过。</response>
        /// <response code="400">请求参数或输入的数据不正确。</response>
        /// <response code="500">服务器发生错误。</response>
        /// <returns>如果返回true,表示支付成功.</returns>
        [HttpPost("[action]")]
        [ProducesResponseType(typeof(OrderDto), 200)]
        [ProducesResponseType(typeof(ErrorMessageDto), 400)]
        [ProducesResponseType(typeof(ErrorMessageDto), 500)]
        public IActionResult WeixinCheckOrderPaymentResult([FromBody] WeipayCheckPaymentResultDto weipayCheckPaymentResultDto)
        {
            WeixinPayService weipayService = (WeixinPayService)this.paymentService.GetChannelService(SourceAppType.DriverApp, PaymentChannelType.Weixin, weipayCheckPaymentResultDto.OSType);
            PaymentRecordDto dto = weipayService.CheckOrder(weipayCheckPaymentResultDto.AppType, weipayCheckPaymentResultDto.PaymentRecordId);
            if (dto != null)
            {
                this.commonPaymentRecordService.UpodatePaymentRecordCheckSignTime(dto.PaymentRecordId);
                PaymentRecordDto paymentRecordDto = this.commonPaymentRecordService.UpdatePaymentRecordStatusSuccess(dto.PaymentRecordId);
                OrderDto orderDto = this.orderProcessService.GetOrder(paymentRecordDto.ReferenceNumber);
                if (paymentRecordDto.OrderType == FlowType.TMSOrder)
                {
                    //查询支付记录的订单类型为订单的：
                    //1.现付，那就自动调用出发。
                    //2.到付，仅更新收货人付款时间
                    if (orderDto.PayMode == PayMode.CurrentlyPay)
                    {
                        if (!orderDto.ShippingPayTime.HasValue)
                        {
                            orderDto = this.orderProcessService.CheckSignCompleteToProcessOrderInformation(OrderPayer.Shipper, orderDto.OrderNo, paymentRecordDto.PaymentRecordId, PaymentChannelType.Alipay, paymentRecordDto.Amount);
                        }
                        int minIndex = orderDto.OrderExtentionInfo.Min(p => p.EndIndex);
                        OrderExtentionDto orderExtentionDto = orderDto.OrderExtentionInfo.Single(p => p.EndIndex == minIndex);
                        OrderStartOutRequestDto orderStartOutRequestDto = new OrderStartOutRequestDto()
                        {
                            AddressType = AddressType.Take,
                            OrderExtentionId = orderExtentionDto.OrderExtentionId,
                            OrderNo = orderDto.OrderNo
                        };
                        return Ok(this.orderProcessService.StartOut(this.Driver, orderStartOutRequestDto));
                    }
                    else if (orderDto.PayMode == PayMode.Collect)
                    {
                        if (!orderDto.ConsigneePayTime.HasValue)
                        {
                            orderDto = this.orderProcessService.CheckSignCompleteToProcessOrderInformation(OrderPayer.Receiver, orderDto.OrderNo, paymentRecordDto.PaymentRecordId, PaymentChannelType.Alipay, paymentRecordDto.Amount);
                        }
                        return Ok(orderDto);
                    }
                    throw new ArgumentException("回单付业务不存在收款");
                }
                else if (paymentRecordDto.OrderType == FlowType.Cod)
                {
                    return Ok(this.orderProcessService.UpdateCodStatusAndTime(orderDto.OrderId, paymentRecordDto.PaymentRecordId));
                }
                else if (paymentRecordDto.OrderType == FlowType.CodAndOrder)
                {
                    //订单和代收货款只存在于收货人付款，并且有代收货款金额的。
                    if (orderDto.PayMode == PayMode.Collect)
                    {
                        if (!orderDto.ConsigneePayTime.HasValue)
                        {
                            orderDto = this.orderProcessService.CheckSignCompleteToProcessOrderInformation(OrderPayer.Receiver, orderDto.OrderNo, paymentRecordDto.PaymentRecordId, PaymentChannelType.Alipay, paymentRecordDto.Amount);
                        }
                        return Ok(orderDto);
                    }
                    throw new ArgumentException("订单及代收货款合并收款，仅支持到付业务");
                }
            }
            throw new ArgumentException("收款查询失败");
        }
        #endregion
        #endregion

        #region 获取提现渠道
        /// <summary>
        /// 获取可用的付款渠道。
        /// </summary>
        /// <param name="osType">操作系统。</param>
        /// <param name="deviceType">设备类型。</param>
        /// <response code="200">付款渠道列表。</response>
        /// <returns></returns>
        [HttpGet("[action]")]
        [ProducesResponseType(typeof(IEnumerable<ChannelDto>), 200)]
        public IActionResult TransferChannels([FromQuery(Name = "os_type")] SourceOSType osType, [FromQuery(Name = "device_type")] DeviceType deviceType)
        {
            PaymentChannelType[] supportedChannels = new PaymentChannelType[] { PaymentChannelType.Alipay, PaymentChannelType.Weixin };

            var channels = this.paymentService.GetChannels(SourceAppType.DriverApp, FlowType.Transfer, osType, this.UserInfo).Where(p => p.ChannelId.AsEnum<PaymentChannelType>().In(supportedChannels));

            return this.Ok(channels);
        }
        #endregion

        #region 获取提现预授权
        /// <summary>
        /// 获取提现预授权。
        /// </summary>
        /// <param name="authLoginRequestDto">预授渠道权信息。</param>
        /// <response code="200">预授权结果。</response>
        /// <response code="400">请求参数或输入的数据不正确。</response>
        /// <response code="401">请求需要认证或者认证信息已过期。</response>
        /// <response code="403">无权访问指定的功能。</response>
        /// <response code="500">服务器发生错误。</response>
        /// <response code="501">某些功能尚未实现。</response>
        /// <returns></returns>
        [HttpPost("[action]")]
        [ProducesResponseType(typeof(Dictionary<string, string>), 200)]
        [ProducesResponseType(typeof(ErrorMessageDto), 400)]
        [ProducesResponseType(typeof(ErrorMessageDto), 500)]
        public IActionResult AppAuthLogin([FromBody] AuthLoginRequestDto authLoginRequestDto)
        {
            if (this.Driver == null)
            {
                throw new ArgumentException("车辆信息不存在");
            }

            IChannelFactoryService channelFactoryService = this.paymentService.GetChannelService(SourceAppType.DriverApp, authLoginRequestDto.ChannelType, authLoginRequestDto.OSType);

            if (channelFactoryService == null)
            {
                throw new ArgumentException("选定的授权渠道暂时无法使用。");
            }
            return this.Ok(channelFactoryService.CreateAppAuthLogin(SourceAppType.DriverApp, authLoginRequestDto.OSType, this.UserInfo));
        }
        #endregion

        #region 授权登录用户的相关信息
        /// <summary>
        /// 授权登录用户的相关信息
        /// </summary>
        /// <param name="authLoginInfoRequestDto">预授渠道权信息。</param>
        /// <response code="200">预授权结果。</response>
        /// <response code="400">请求参数或输入的数据不正确。</response>
        /// <response code="401">请求需要认证或者认证信息已过期。</response>
        /// <response code="403">无权访问指定的功能。</response>
        /// <response code="500">服务器发生错误。</response>
        /// <response code="501">某些功能尚未实现。</response>
        /// <returns></returns>
        [HttpPost("[action]")]
        [ProducesResponseType(typeof(Dictionary<string, object>), 200)]
        [ProducesResponseType(typeof(ErrorMessageDto), 400)]
        [ProducesResponseType(typeof(ErrorMessageDto), 500)]
        public IActionResult AuthLoginInfo([FromBody] AuthLoginInfoRequestDto authLoginInfoRequestDto)
        {
            if (this.Driver == null)
            {
                throw new ArgumentException("车辆信息不存在");
            }
            IChannelFactoryService channelService = this.paymentService.GetChannelService(SourceAppType.DriverApp, authLoginInfoRequestDto.ChannelType, authLoginInfoRequestDto.OSType);

            if (channelService == null)
            {
                throw new ArgumentException("选定的授权渠道暂时无法使用。");
            }

            return this.Ok(channelService.AuthLoginInfo(authLoginInfoRequestDto.Parameters["auth_code"], SourceAppType.DriverApp, authLoginInfoRequestDto.OSType, this.UserInfo));
        }
        #endregion

        #region 创建余额充值请求
        /// <summary>
        /// 创建余额充值请求。
        /// </summary>
        /// <param name="dto">付款请求信息。</param>
        /// <response code="200">付款结果。</response>
        /// <response code="400">请求参数或输入的数据不正确。</response>
        /// <response code="401">请求需要认证或者认证信息已过期。</response>
        /// <response code="403">无权访问指定的功能。</response>
        /// <response code="500">服务器发生错误。</response>
        /// <response code="501">某些功能尚未实现。</response>
        /// <returns></returns>
        [HttpPost("[action]")]
        [ProducesResponseType(typeof(PaymentDto), 200)]
        [ProducesResponseType(typeof(ErrorMessageDto), 400)]
        [ProducesResponseType(typeof(ErrorMessageDto), 500)]
        public IActionResult BalanceRecharge([FromBody] RechargeRequestDto dto)
        {
            IChannelFactoryService channelService = this.paymentService.GetChannelService(SourceAppType.DriverApp, dto.ChannelType, dto.OSType);

            if (channelService == null)
            {
                throw new ArgumentException("选定的付款渠道暂时无法使用。");
            }

            decimal originalAmount = dto.Amount;

            string rechargeNo = string.Empty;

            if (dto.OrderType == FlowType.Recharge)
            {
                rechargeNo = RandomCode.GeneratePaymentOrderNo();
            }
            if (originalAmount <= 0)
            {
                throw new NotImplementedException();
            }
            string ip = Request.HttpContext.Connection.RemoteIpAddress.ToString();
#if DEBUG
            ip = "192.168.1.1";
#endif

            PaymentDto paymentDto = channelService.TryPay(SourceAppType.DriverApp, dto.OrderType, "BalanceRecharge", rechargeNo, dto.OSType, dto.DeviceType, dto.DeviceId, dto.Parameters, originalAmount, null, this.UserInfo);

            return this.Ok(paymentDto);
        }

        /// <summary>
        /// 余额充值验签（支付宝、微信、银行卡使用此接口）
        /// </summary>
        /// <param name="rechargeRequestDto">余额充值付款请求信息。</param>
        /// <response code="200">订单付款二维码信息。</response>
        /// <response code="400">请求参数或输入的数据不正确。</response>
        /// <response code="401">请求需要认证或者认证信息已过期。</response>
        /// <response code="403">无权访问指定的功能。</response>
        /// <response code="500">服务器发生错误。</response>
        /// <response code="501">某些功能尚未实现。</response>
        /// <returns></returns>
        [HttpPost("[action]")]
        [ProducesResponseType(typeof(OkObjectResult), 200)]
        [ProducesResponseType(typeof(ErrorMessageDto), 400)]
        [ProducesResponseType(typeof(ErrorMessageDto), 500)]
        public IActionResult RechargeCheckSign([FromBody] RechargeRequestDto rechargeRequestDto)
        {
            if (rechargeRequestDto.ChannelType == PaymentChannelType.Balance)
            {
                throw new ArgumentException("此方法不支持余额支付");
            }
            //if (rechargeRequestDto.ChannelType == PaymentChannelType.Cash)
            //{
            //    throw new ArgumentException("此方法不支持线下支付");
            //}
            if (rechargeRequestDto.ChannelType == PaymentChannelType.BankCard)
            {
                throw new ArgumentException("此方法暂不支持银行卡支付");
            }
            IChannelFactoryService channelFactoryService = this.paymentService.GetChannelService(SourceAppType.DriverApp, rechargeRequestDto.ChannelType, rechargeRequestDto.OSType);

            if (channelFactoryService == null)
            {
                throw new ArgumentException("选定的付款渠道暂时无法使用。");
            }

            if (rechargeRequestDto.OrderType != FlowType.Recharge)
            {
                throw new ArgumentException("付款订单类型仅支持余额充值，不支持其他类型");
            }
            string ip = Request.HttpContext.Connection.RemoteIpAddress.ToString();
#if DEBUG
            ip = "192.168.1.1";
#endif
            if (rechargeRequestDto.ChannelType == PaymentChannelType.Alipay)
            {
                if (rechargeRequestDto.Parameters == null || rechargeRequestDto.Parameters.Count == 0)
                {
                    throw new ArgumentException("网络平台使用费验签缺少必要信息,请检查Parameters是否存在信息");
                }
            }
            PaymentRecordDto paymentRecordDto = channelFactoryService.SyncCheckSign(rechargeRequestDto.Parameters);

            if (paymentRecordDto.CheckSignTime.HasValue)
            {

                //PaymentDto paymentDto = new PaymentDto()
                //{
                //    PaymentRecordId = paymentRecordDto.PaymentRecordId,
                //    OrderType = paymentRecordDto.OrderType,
                //    ReferenceNumber = paymentRecordDto.ReferenceNumber,
                //    PayChannelType = rechargeRequestDto.ChannelType,
                //    OriginalAmount = paymentRecordDto.Amount,
                //    Discount = 0M,
                //    PaidAmount = paymentRecordDto.Amount,
                //    Result = PaymentResultType.Success
                //};
                //this.commonPaymentRecordService.UpdatePaymentRecordStatusSuccess(paymentRecordDto.PaymentRecordId);
                //WalletDto walletDto = this.walletService.GetWalletByUserId(this.User.UserId);
                //UserFlowRecordDto userFlowRecordDto = new UserFlowRecordDto()
                //{
                //    Balance = walletDto.Balance,
                //    Amount = paymentRecordDto.Amount,
                //    CreateTime = DateTime.Now,
                //    Remark = $"{ FlowType.Recharge.GetDescriptionString()}: {paymentRecordDto.Amount.ToString("N")}元",
                //    FlowDirection = FlowDirectionType.Income,
                //    FlowType = FlowType.Recharge,
                //    Channel = rechargeRequestDto.ChannelType,
                //    UserId = this.User.UserId,
                //    UserName = this.User.UserName
                //};
                //this.userFlowRecordService.AddAsync(userFlowRecordDto);
            }
            return this.Ok();
        }

        #endregion

    }
}
